//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics.Contracts;
using System.Reflection;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Formats.Biff.Tokens;

namespace OpenLS.Spreadsheet.Formats.Biff
{
static class FormulaTokenFactory
    {
#if DEBUG
    static public  void TestTokens()
    {
        foreach (var value in typeof(FormulaTokenFactory).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static) )
        {
            FormulaTokenId id = (FormulaTokenId) value.GetValue(null);
            object dummy = GetToken(id);
        }
    }
#endif
        public static FormulaToken GetToken(FormulaTokenId id)
        {
            Contract.Ensures(Contract.Result<FormulaToken>() != null);
            Contract.Ensures(Contract.Result<FormulaToken>().TokenId == id);
            switch (id)
            {
                case FormulaTokenId.Bool:
                    return new BooleanToken();
                case FormulaTokenId.Err:
                    return new ErrorToken();
                case FormulaTokenId.Int:
                    return new IntegerToken();
                case FormulaTokenId.Add:
                    return new BinaryToken(BinaryOperatorType.Add);
                case FormulaTokenId.Sub:
                    return new BinaryToken(BinaryOperatorType.Subtract);
                case FormulaTokenId.Mul:
                    return new BinaryToken(BinaryOperatorType.Multiply);
                case FormulaTokenId.Div:
                    return new BinaryToken(BinaryOperatorType.Divide);
                case FormulaTokenId.Power:
                    return new BinaryToken(BinaryOperatorType.Power);
                case FormulaTokenId.GT:
                    return new BinaryToken(BinaryOperatorType.GreaterThan);
                case FormulaTokenId.GE:
                    return new BinaryToken(BinaryOperatorType.GreaterThanOrEqual);
                case FormulaTokenId.LT:
                    return new BinaryToken(BinaryOperatorType.LessThan);
                case FormulaTokenId.LE:
                    return new BinaryToken(BinaryOperatorType.LessThanOrEqual);
                case FormulaTokenId.EQ:
                    return new BinaryToken(BinaryOperatorType.Equality);
                case FormulaTokenId.NE:
                    return new BinaryToken(BinaryOperatorType.Inequality);
                case FormulaTokenId.Uminus:
                    return new UnaryToken(UnaryOperatorType.Subtract);
                case FormulaTokenId.Uplus:
                    return new UnaryToken(UnaryOperatorType.Add);

                case FormulaTokenId.RefNV:
                    return new RefNToken(AccessorType.Value);
                case FormulaTokenId.RefN:
                    return new RefNToken(AccessorType.Reference);
                case FormulaTokenId.RefNA:
                    return new RefNToken(AccessorType.Array);

                case FormulaTokenId.RefV:
                    return new RefToken(AccessorType.Value);
                case FormulaTokenId.Ref:
                    return new RefToken(AccessorType.Reference);
                case FormulaTokenId.RefA:
                    return new RefToken(AccessorType.Array);

                case FormulaTokenId.Ref3dV:
                    return new Ref3DToken(AccessorType.Value);
                case FormulaTokenId.Ref3d:
                    return new Ref3DToken(AccessorType.Reference);
                case FormulaTokenId.Ref3dA:
                    return new Ref3DToken(AccessorType.Array);

                case FormulaTokenId.NameA:
                    return new NameToken(AccessorType.Array);
                case FormulaTokenId.Name:
                    return new NameToken(AccessorType.Reference);
                case FormulaTokenId.NameV:
                    return new NameToken(AccessorType.Value);

                case FormulaTokenId.NameXA:
                    return new NameXToken(AccessorType.Array);
                case FormulaTokenId.NameX:
                    return new NameXToken(AccessorType.Reference);
                case FormulaTokenId.NameXV:
                    return new NameXToken(AccessorType.Value);
                case FormulaTokenId.Str:
                    return new StringConstantToken();

                case FormulaTokenId.FuncVarA:
                    return new FunctionVarToken(AccessorType.Array);
                case FormulaTokenId.FuncVar:
                    return new FunctionVarToken(AccessorType.Reference);
                case FormulaTokenId.FuncVarV:
                    return new FunctionVarToken(AccessorType.Value);
               
                case FormulaTokenId.FuncA:
                    return new FunctionToken(AccessorType.Array);
                case FormulaTokenId.Func:
                    return new FunctionToken(AccessorType.Reference);
                case FormulaTokenId.FuncV:
                    return new FunctionToken(AccessorType.Value);
                case FormulaTokenId.Exp:
                    return new ArrayFormulaReferenceToken();
                case FormulaTokenId.Paren:
                    return new ParenthesesToken();
                case FormulaTokenId.Area3dA:
                    return new Area3DToken(AccessorType.Array);
                case FormulaTokenId.Area3d:
                    return new Area3DToken(AccessorType.Reference);
                case FormulaTokenId.Area3dV:
                    return new Area3DToken(AccessorType.Value);

                case FormulaTokenId.AreaA:
                    return new AreaToken(AccessorType.Array);
                case FormulaTokenId.Area:
                    return new AreaToken(AccessorType.Reference);
                case FormulaTokenId.AreaV:
                    return new AreaToken(AccessorType.Value);
                
                case FormulaTokenId.AreaNA:
                    return new AreaNToken(AccessorType.Array);
                case FormulaTokenId.AreaN:
                    return new AreaNToken(AccessorType.Reference);
                case FormulaTokenId.AreaNV:
                    return new AreaNToken(AccessorType.Value);
                case FormulaTokenId.Attr:
                    return new AttributeToken();
                case FormulaTokenId.Num:
                    return new NumberToken();

                case FormulaTokenId.RefErrA:
                    return new RefErrorToken(AccessorType.Array);
                case FormulaTokenId.RefErr:
                    return new RefErrorToken(AccessorType.Reference);
                case FormulaTokenId.RefErrV:
                    return new RefErrorToken(AccessorType.Value);

                case FormulaTokenId.RefErr3dA:
                    return new RefError3DToken(AccessorType.Array);
                case FormulaTokenId.RefErr3d:
                    return new RefError3DToken(AccessorType.Reference);
                case FormulaTokenId.RefErr3dV:
                    return new RefError3DToken(AccessorType.Value);


                case FormulaTokenId.AreaErr3dA:
                    return new AreaError3DToken(AccessorType.Array);
                case FormulaTokenId.AreaErr3d:
                    return new AreaError3DToken(AccessorType.Reference);
                case FormulaTokenId.AreaErr3dV:
                    return new AreaError3DToken(AccessorType.Value);

                case FormulaTokenId.AreaErrA:
                    return new AreaErrorToken(AccessorType.Array);
                case FormulaTokenId.AreaErr:
                    return new AreaErrorToken(AccessorType.Reference);
                case FormulaTokenId.AreaErrV:
                    return new AreaErrorToken(AccessorType.Value);
                case FormulaTokenId.ArrayA:
                    return new ArrayToken(AccessorType.Array);
                case FormulaTokenId.Array:
                    return new ArrayToken(AccessorType.Reference);
                case FormulaTokenId.ArrayV:
                    return new ArrayToken(AccessorType.Value);
                case FormulaTokenId.Concat:
                    return new ConcatToken();



                case FormulaTokenId.MemAreaA:
                    return new MemAreaToken(AccessorType.Array);
                case FormulaTokenId.MemArea:
                    return new MemAreaToken(AccessorType.Reference);
                case FormulaTokenId.MemAreaV:
                    return new MemAreaToken(AccessorType.Value);

                case FormulaTokenId.MemAreaNA:
                    return new MemAreaNToken(AccessorType.Array);
                case FormulaTokenId.MemAreaN:
                    return new MemAreaNToken(AccessorType.Reference);
                case FormulaTokenId.MemAreaNV:
                    return new MemAreaNToken(AccessorType.Value);
                
                case FormulaTokenId.MemErrA:
                    return new MemErrorToken(AccessorType.Array);
                case FormulaTokenId.MemErr:
                    return new MemErrorToken(AccessorType.Reference);
                case FormulaTokenId.MemErrV:
                    return new MemErrorToken(AccessorType.Value);
                case FormulaTokenId.MemFuncA:
                    return new MemFuncToken(AccessorType.Array);
                case FormulaTokenId.MemFunc:
                    return new MemFuncToken(AccessorType.Reference);
                case FormulaTokenId.MemFuncV:
                    return new MemFuncToken(AccessorType.Value);

                case FormulaTokenId.MemNoMemA:
                    return new MemNoMemToken(AccessorType.Array);
                case FormulaTokenId.MemNoMem:
                    return new MemNoMemToken(AccessorType.Reference);
                case FormulaTokenId.MemNoMemV:
                    return new MemNoMemToken(AccessorType.Value);
                
                case FormulaTokenId.MemNoMemNA:
                    return new MemNoMemNToken(AccessorType.Array);
                case FormulaTokenId.MemNoMemN:
                    return new MemNoMemNToken(AccessorType.Reference);
                case FormulaTokenId.MemNoMemNV:
                    return new MemNoMemNToken(AccessorType.Value);

                case FormulaTokenId.None:
                    return new NoneToken();

                case FormulaTokenId.Percent:
                    return new PercentToken();

                case FormulaTokenId.MissArg:
                    return new MissingArgumentToken();

                case FormulaTokenId.Sheet:
                    return new SheetToken();
                case FormulaTokenId.Range:
                    return new BoundingRangeToken();
                case FormulaTokenId.Isect:
                    return new CellRangeIntersectionToken();
                case FormulaTokenId.Union:
                    return new RangeListToken();
                case FormulaTokenId.EndSheet:
                    return new EndSheetToken();
                case FormulaTokenId.Extended:
                    return new ExtendedToken();

                case FormulaTokenId.FuncCEA:
                    return new FunctionCeToken(AccessorType.Array);
                case FormulaTokenId.FuncCE:
                    return new FunctionCeToken(AccessorType.Reference);
                case FormulaTokenId.FuncCEV:
                    return new FunctionCeToken(AccessorType.Value);
                case FormulaTokenId.Tbl:
                    return new TableToken();


                default:
                    throw new NotImplementedException(id.ToString());
            }
        }
    }
}